﻿using System;
using System.Collections.Specialized;
using System.Linq;
using Loki.Commands;
using Loki.Engine;

namespace Loki.UI
{
    public abstract class ContainerViewModel<TModel> : ViewModel<TModel>, IContainerViewModel
    {
        public ContainerViewModel()
        {
            _SubModels = CreateTrackedCollection<ViewModel<TModel>>();
            _SubModels.TrackDeleted = false;
            _SubModels.CollectionChanged += SubModels_CollectionChanged;
        }

        protected override void SubCollection_ItemChanged<T>(object P_Sender, ItemChangedEventArgs<T> e)
        {
            if (e.Item is ISubViewModel)
            {
                base.SubCollection_ItemChanged(P_Sender, e);
            }
        }

        private void SubModels_CollectionChanged(object P_Sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (var L_SubModel in e.NewItems)
                {
                    if (L_SubModel is ISubViewModel)
                    {
                        ((ISubViewModel)L_SubModel).Parent = this;
                    }
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                foreach (var L_SubModel in _SubModels)
                {
                    if (L_SubModel is ISubViewModel)
                    {
                        ((ISubViewModel)L_SubModel).Parent = this;
                    }
                }
            }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            foreach (var L_VM in _SubModels)
            {
                L_VM.Initialize();
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            foreach (var L_VM in _SubModels)
            {
                L_VM.LoadData();
            }
        }

        protected override void OnStart(EventArgs e)
        {
            base.OnStart(e);
            foreach (var L_VM in _SubModels)
            {
                if (L_VM.IsActive)
                {
                    L_VM.StartInteraction();
                }
            }
        }

        public ILokiEnumerable<IViewModel> SubModels
        {
            get { return this._SubModels; }
        }

        private LokiCollection<ViewModel<TModel>> _SubModels;

        protected override bool ValidateData(ValidationMode P_Mode)
        {
            bool L_Return = true;
            foreach (var L_VM in _SubModels)
            {
                L_VM.IsValid = true;
                L_VM.Validate.Execute(P_Mode);
                L_Return &= L_VM.IsValid;
            }

            return L_Return;
        }

        protected TViewModel ActivateOrAdd<TViewModel>() where TViewModel : ViewModel<TModel>
        {
            return ActivateOrAdd<TViewModel>(null, null);
        }

        protected TViewModel ActivateOrAdd<TViewModel>(Func<TViewModel, bool> P_Selector) where TViewModel : ViewModel<TModel>
        {
            return ActivateOrAdd<TViewModel>(P_Selector, null);
        }

        protected TViewModel ActivateOrAdd<TViewModel>(Action<TViewModel> P_Initializer)
            where TViewModel : ViewModel<TModel>
        {
            return ActivateOrAdd<TViewModel>(null, P_Initializer);
        }

        protected TViewModel ActivateOrAdd<TViewModel>(Func<TViewModel, bool> P_Selector, Action<TViewModel> P_Initializer)
            where TViewModel : ViewModel<TModel>
        {
            // search
            TViewModel L_Model = null;
            if (P_Selector != null)
            {
                L_Model = _SubModels.Where(x => x is TViewModel).Cast<TViewModel>().FirstOrDefault(x => P_Selector(x));
            }
            else
            {
                L_Model = _SubModels.FirstOrDefault(x => x is TViewModel) as TViewModel;
            }

            // init
            if (L_Model == null)
            {
                L_Model = AddNew<TViewModel>(P_Initializer);
            }

            L_Model.Activate.Execute(null);

            return L_Model;
        }

        protected TViewModel AddNew<TViewModel>() where TViewModel : ViewModel<TModel>
        {
            return AddNew<TViewModel>(null);
        }

        protected TViewModel AddNew<TViewModel>(Action<TViewModel> P_Initializer) where TViewModel : ViewModel<TModel>
        {
            TViewModel L_NewModel = ContextHelper.GetViewModel<TViewModel>();

            AddSubModel(L_NewModel, P_Initializer);
            return L_NewModel;
        }

        private void AddSubModel<TViewModel>(TViewModel P_Model, Action<TViewModel> P_Initializer) where TViewModel : ViewModel<TModel>
        {
            if (P_Initializer != null)
            {
                P_Initializer(P_Model);
            }

            Commands.Handle(P_Model.Close, (s, e) => SubModel_Close(P_Model, e));
            _SubModels.Add(P_Model);
        }

        private void SubModel_Close(ViewModel<TModel> P_Model, CommandEventArgs P_Args)
        {
            Commands.UnHandle(P_Model.Close);
            _SubModels.Remove(P_Model);
        }

        public override void BeginInit()
        {
            foreach (var L_SubModel in _SubModels)
            {
                L_SubModel.BeginInit();
            }
        }

        public override void EndInit(bool P_IsStable)
        {
            foreach (var L_SubModel in _SubModels)
            {
                L_SubModel.EndInit(P_IsStable);
            }

            base.EndInit(P_IsStable);
        }

        public override void AcceptChanges()
        {
            foreach (var L_SubModel in _SubModels)
            {
                L_SubModel.AcceptChanges();
            }

            base.AcceptChanges();
        }
    }
}
